package jackson.util;

import org.springframework.beans.*;
import org.springframework.objenesis.ObjenesisHelper;

import java.beans.PropertyDescriptor;
import java.util.*;
import java.util.function.Supplier;

public abstract class BeanUtil extends BeanUtils {
    public static <T> T newInstance(Class<T> clazz) {
        return ObjenesisHelper.newInstance(clazz);
    }

    /**
     * Map 转 Bean
     */
    public static <T> T mapToBean(Map<String, Object> sources, Class<T> target) {
        T t = BeanUtils.instantiateClass(target);
        BeanWrapper beanWrapper = new BeanWrapperImpl(t);
        beanWrapper.setPropertyValues(new MutablePropertyValues(sources), true, true);
        return t;
    }

    /**
     * Bean 转 Map
     */
    public static Map<String, Object> beanToMap(Object sources) {
        Map<String, Object> target = new HashMap<>();
        BeanWrapper beanWrapper = new BeanWrapperImpl(sources);
        PropertyDescriptor[] descriptor = beanWrapper.getPropertyDescriptors();
        for (PropertyDescriptor pd : descriptor) {
            target.put(pd.getName(), beanWrapper.getPropertyValue(pd.getName()));
        }
        return target;
    }

    /**
     * S 转 T
     */
    public static <S, T> T copyProperties(S source, Supplier<T> target) throws BeansException {
        return copyProperties(source, target, (s, t) -> {
        });
    }

    /**
     * S 转 T
     *
     * @param callBack 过程中的回调
     */
    public static <S, T> T copyProperties(S source, Supplier<T> target, BeanConvertCallBack<S, T> callBack) throws BeansException {
        T t = target.get();
        copyProperties(source, t);
        if (callBack != null) {
            callBack.callBack(source, t); // 回调
        }
        return t;
    }

    /**
     * List<S> 转 List<T>
     */
    public static <S, T> List<T> copyListProperties(Collection<S> sources, Supplier<T> target) {
        return copyListProperties(sources, target, null);
    }

    /**
     * List<S> 转 List<T>
     *
     * @param callBack 过程中的回调
     */
    public static <S, T> List<T> copyListProperties(Collection<S> sources, Supplier<T> target, BeanConvertCallBack<S, T> callBack) {
        if (sources == null || target == null) {
            return null;
        }
        List<T> list = new ArrayList<>(sources.size());
        for (S source : sources) {
            T t = target.get();
            copyProperties(source, t);
            if (callBack != null) {
                callBack.callBack(source, t); // 回调
            }
            list.add(t);
        }
        return list;
    }

    @FunctionalInterface
    public interface BeanConvertCallBack<S, T> {
        void callBack(S s, T t);
    }
}